<?php

namespace Yxy\YWechat;

use EasyWeChat\Kernel\Exceptions\BadResponseException;
use EasyWeChat\Kernel\Exceptions\HttpException;
use EasyWeChat\Kernel\Exceptions\InvalidArgumentException;
use EasyWeChat\MiniApp\Application;
use Exception;
use Godruoyi\Snowflake\SnowflakeException;
use Symfony\Contracts\HttpClient\Exception\ClientExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\DecodingExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\RedirectionExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\ServerExceptionInterface;
use Symfony\Contracts\HttpClient\Exception\TransportExceptionInterface;
use Yxy\YUtil\Utils;

/**
 * 微信小程序
 */
class Mini
{
    /**
     * 小程序app
     * @var Application
     */
    protected static Application $app;

    /**
     * 初始化小程序
     * @return void
     * @throws InvalidArgumentException
     * @throws Exception
     */
    protected static function initApp(): void
    {
        $appid = config('ywechat.mini.appid');
        $secret = config('ywechat.mini.secret');
        if (empty($appid) || empty($secret)) {
            throw new Exception("请先填写微信小程序配置");
        }
        self::$app = new Application([
            'app_id' => config('ywechat.mini.appid'),
            'secret' => config('ywechat.mini.secret'),
        ]);
    }

    /**
     * 获取小程序app
     * @return Application
     * @throws InvalidArgumentException
     */
    public static function getApp(): Application
    {
        if (empty(self::$app)) {
            self::initApp();
        }
        return self::$app;
    }

    /**
     * 获取登录信息
     * @param string $code 授权码
     * @return array
     * @throws InvalidArgumentException
     * @throws HttpException
     * @throws ClientExceptionInterface
     * @throws DecodingExceptionInterface
     * @throws RedirectionExceptionInterface
     * @throws ServerExceptionInterface
     * @throws TransportExceptionInterface
     */
    public static function login(string $code): array
    {
        $utils = self::getApp()->getUtils();
        // 获取微信信息
        return $utils->codeToSession($code);
    }

    /**
     * @param string $code 授权码
     * @return mixed
     * @throws BadResponseException
     * @throws ClientExceptionInterface
     * @throws DecodingExceptionInterface
     * @throws InvalidArgumentException
     * @throws RedirectionExceptionInterface
     * @throws ServerExceptionInterface
     * @throws TransportExceptionInterface
     */
    public static function phoneNumber(string $code): mixed
    {
        $result = self::getApp()->getClient()->postJson('wxa/business/getuserphonenumber', ['code' => $code])->toArray();
        return $result['phone_info']['phoneNumber'];
    }

    /**
     * 保存文件
     * @param $data
     * @return array
     * @throws SnowflakeException
     */
    protected static function saveFile($data): array
    {
        [$uploadPath, $filePath] = Utils::makeFilePath('wechat-qrcode');

        file_put_contents($uploadPath, $data);

        return [
            'url' => $filePath,
            'show' => Utils::getHttpPath($filePath)
        ];
    }

    /**
     * 生成二维码
     * @param string $data 要传递的参数
     * @param string $page 跳转的页面  默认首页
     * @param int $width 大小  默认 500
     * @param bool $check_path 检查page 是否存在 默认不检查
     * @param int $env_version 正式版为 1，体验版为 2，开发版为 3
     * @return array
     * @throws ClientExceptionInterface
     * @throws InvalidArgumentException
     * @throws RedirectionExceptionInterface
     * @throws ServerExceptionInterface
     * @throws TransportExceptionInterface|SnowflakeException
     */
    public static function getQrCode(
        string $data,
        string $page = 'pages/index/index',
        int    $width = 500,
        bool   $check_path = false,
        int    $env_version = 1
    ): array
    {
        $version_array = [1 => 'release', 2 => 'trial', 3 => 'develop'];
        if (!isset($version_array[$env_version])) {
            $env_version = 1;
        }

        $response = self::getApp()->getClient()->postJson('/wxa/getwxacodeunlimit', [
            'scene' => $data,
            'page' => $page,
            'width' => $width,
            'check_path' => $check_path,
            'env_version' => $version_array[$env_version],
        ]);

        return self::saveFile($response->getContent());
    }
}